package com.yin.waimai.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yin.waimai.annotation.SensitiveOperation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 敏感操作日志切面
 */
@Aspect
@Component
public class SensitiveOperationLogAspect {
    
    private static final Logger log = LoggerFactory.getLogger(SensitiveOperationLogAspect.class);
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 环绕通知，拦截标记了@SensitiveOperation注解的方法
     */
    @Around("@annotation(com.yin.waimai.annotation.SensitiveOperation)")
    public Object logSensitiveOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        Exception exception = null;
        
        try {
            // 执行原方法
            result = joinPoint.proceed();
            return result;
        } catch (Exception e) {
            exception = e;
            throw e;
        } finally {
            try {
                // 记录日志
                saveOperationLog(joinPoint, result, exception, System.currentTimeMillis() - startTime);
            } catch (Exception e) {
                log.error("记录操作日志失败", e);
            }
        }
    }
    
    /**
     * 保存操作日志
     */
    private void saveOperationLog(ProceedingJoinPoint joinPoint, Object result, Exception exception, long executionTime) throws Exception {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        // 获取注解信息
        SensitiveOperation sensitiveOperation = method.getAnnotation(SensitiveOperation.class);
        
        // 获取当前用户信息
        String operatorUsername = "";
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            operatorUsername = authentication.getName();
        }
        
        // 获取请求IP
        String ip = "";
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            ip = getIpAddress(request);
        }
        
        // 记录日志到控制台（实际项目中可以保存到数据库）
        log.info("敏感操作日志: 操作={}, 类型={}, 方法={}, 参数={}, 结果={}, 用户={}, IP={}, 执行时间={}ms", 
                sensitiveOperation.value(), 
                sensitiveOperation.operationType(),
                method.getDeclaringClass().getName() + "." + method.getName(), 
                Arrays.toString(joinPoint.getArgs()), 
                exception != null ? "异常: " + exception.getMessage() : "成功", 
                operatorUsername,
                ip,
                executionTime);
    }
    
    /**
     * 获取请求IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}